using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
using System.Web;
using System.Web.Routing;
using System.Web.UI;
using ManagedUIFlow.Infrastructure.Flows;
using ManagedUIFlow.Infrastructure.Services;
using ManagedUIFlow.Model;
using Moq;
using Xunit;

namespace ManagedUIFlow.Specs.Infrastructure.Services
{
    public class ContinuationSessionFlowViewServSpecs
    {
        private readonly ContinuationSessionFlowViewService _service;
        private readonly RequestContext _requestContext;
        private readonly Mock<HttpContextBase> _contextMock;
        private readonly Mock<HttpSessionStateBase> _sessionMock;
        private readonly RouteData _routeData;

        public ContinuationSessionFlowViewServSpecs()
        {
            _service = new ContinuationSessionFlowViewService();
            _contextMock = new Mock<HttpContextBase>();
            _routeData = new RouteData();
            _sessionMock = new Mock<HttpSessionStateBase>();
            _contextMock.Setup(c => c.Session).Returns(_sessionMock.Object);
            _requestContext = new RequestContext(_contextMock.Object, _routeData);
        }
      
        [Fact]
        public void NoFlowExistsToDeserialize_Throws()
        {
            var flowDefinition = new Flow("foo", "", RedirectBehavior.Auto, "");
            var flowServiceMock = new Mock<FlowService>();
            flowServiceMock.Setup(s => s.GetFlowDefinition("foo")).Returns(flowDefinition);
            _service.FlowService = flowServiceMock.Object;

            Assert.Throws<FlowException>(() => _service.Deserialize("foo", _requestContext));
        }       
      
        [Fact]
        public void DserializingExistingFlow_TransitionsFlow()
        {
            var key = Guid.NewGuid().ToString();            
            var flow = new ManagedFlow("foo");
            var formatter = new LosFormatter();
            var strBuilder = new StringBuilder();
            var strWriter = new StringWriter(strBuilder);
            formatter.Serialize(strWriter, flow);            
            var queue = new Dictionary<string, Dictionary<string, string>>
                            {
                                {
                                    flow.Key.ToString(), new Dictionary<string, string>
                                                             {
                                                                 {key, strBuilder.ToString()}
                                                             }
                                    }
                            };
            flow.SetNavigation("bar");
            _sessionMock.Setup(s => s[ContinuationSessionFlowViewService.SessionSerializerServiceQueue]).Returns(queue);
            var flowServiceMock = new Mock<FlowService>();            
            _service.FlowService = flowServiceMock.Object;

            var runningFlow = _service.Deserialize(key, _requestContext);

            Assert.NotNull(runningFlow);
            flowServiceMock.Verify(s => s.GetNavigationFor(It.IsAny<string>(), It.IsAny<string>(), It.IsAny<string>()));
        }
             
        [Fact]
        public void SerializeFlow_PersistsinSessionState()
        {
            _routeData.Values.Add("controller", "foo");
            var flow = new ManagedFlow(Guid.NewGuid(), "foo", "bar", RedirectBehavior.Manual, "");            

            var key = _service.Serialize(flow, _requestContext);

            Assert.NotNull(key);            
        }

        [Fact]
        public void PostRedirectGet_IssuesRedirect()
        {
            _routeData.Values.Add("controller", "foo");
            var flow = new ManagedFlow(Guid.NewGuid(), "foo", "bar", RedirectBehavior.Auto, "");
            var responseMock = new Mock<HttpResponseBase>();
            responseMock.Setup(r => r.Redirect(It.IsAny<string>())).Verifiable();
            _contextMock.Setup(c => c.Response).Returns(responseMock.Object);
            _sessionMock.Setup(s => s.Add(BasicSessionFlowViewService.RedirectUrlKey, It.IsAny<string>())).Callback(
                (string name, object value) =>
                _sessionMock.Setup(s => s[BasicSessionFlowViewService.RedirectUrlKey]).Returns(value));
            _sessionMock.Setup(s => s.Add(BasicSessionFlowViewService.RedirectTicketKey, flow)).Verifiable();

            _service.PostRedirectGet(Guid.NewGuid().ToString(), flow, _requestContext);

            _sessionMock.Verify();
            responseMock.Verify();
        }

        [Fact]
        public void PostRedirectGet_NeverIssuesRedirectBack()
        {
            _routeData.Values.Add("controller", "foo");
            var flow = new ManagedFlow(Guid.NewGuid(), "foo", "bar", RedirectBehavior.Auto, "");
            var responseMock = new Mock<HttpResponseBase>();
            _contextMock.Setup(c => c.Response).Returns(responseMock.Object);
            _sessionMock.Setup(s => s[BasicSessionFlowViewService.RedirectTicketKey]).Returns(flow);

            _service.PostRedirectGet(Guid.NewGuid().ToString(), flow, _requestContext);

            _sessionMock.Verify(s => s.Add(BasicSessionFlowViewService.RedirectUrlKey, It.IsAny<string>()), Times.Never());
            responseMock.Verify();
        }
    }
}